package com.yyy.tcc.service.compensation;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * 演示ABA问题及其解决方案
 */
public class ABADemo {
    public static void main(String[] args) throws InterruptedException {
        // 演示普通AtomicReference的ABA问题
//        demonstrateABAProblem();

        // 演示AtomicStampedReference如何解决ABA问题
        demonstrateABASolution();
    }

    /**
     * 演示ABA问题的产生
     */
    private static void demonstrateABAProblem() throws InterruptedException {
        AtomicInteger atomicInt = new AtomicInteger(100);

        Thread t1 = new Thread(() -> {
            // 先把100改成101，再改回100
            atomicInt.compareAndSet(100, 101);
            atomicInt.compareAndSet(101, 100);
            System.out.println("t1完成了ABA操作: 100->101->100");
        });

        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(100); // 确保t1先执行
                // t2看到的还是100，但实际上已经经历了100->101->100的变化
                boolean success = atomicInt.compareAndSet(100, 200);
                System.out.println("t2修改结果: " + success + " (检测不出ABA)");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }

    /**
     * 演示如何使用AtomicStampedReference解决ABA问题
     */
    private static void demonstrateABASolution() throws InterruptedException {
        // 初始值是100，初始版本号是0
        AtomicStampedReference<Integer> atomicStampedRef =
            new AtomicStampedReference<>(100, 0);

        Thread t1 = new Thread(() -> {
            // 获取当前版本号
            int stamp = atomicStampedRef.getStamp();
            System.out.println("t1第一次读取: 值=" + atomicStampedRef.getReference()
                             + ", 版本号=" + stamp);

            // 将100改成101，版本号+1
            boolean success1 = atomicStampedRef.compareAndSet(100, 101,
                                                            stamp, stamp + 1);
            System.out.println("t1第一次修改: 100->101, 结果=" + success1
                             + ", 新版本号=" + atomicStampedRef.getStamp());

            // 将101改回100，版本号再+1
            success1 = atomicStampedRef.compareAndSet(101, 100,
                                                     stamp + 1, stamp + 2);
            System.out.println("t1第二次修改: 101->100, 结果=" + success1
                             + ", 新版本号=" + atomicStampedRef.getStamp());
        });

        Thread t2 = new Thread(() -> {
            try {
                // 获取初始版本号
                int stamp = atomicStampedRef.getStamp();
                int reference = atomicStampedRef.getReference();
                System.out.println("t2第一次读取: 值=" + reference
                                 + ", 版本号=" + stamp);

                Thread.sleep(100); // 等待t1完成ABA操作

                // 尝试更新，使用旧版本号，会失败
                boolean success = atomicStampedRef.compareAndSet(reference, 200,
                                                               stamp, stamp + 1);
                System.out.println("t2尝试修改: 值=" + reference + "->200"
                                 + ", 使用版本号=" + stamp
                                 + ", 当前版本号=" + atomicStampedRef.getStamp()
                                 + ", 结果=" + success + " (能够检测出ABA)");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("最终结果: 值=" + atomicStampedRef.getReference()
                         + ", 版本号=" + atomicStampedRef.getStamp());
    }
}
